home *** CD-ROM | disk | FTP | other *** search
Wrap
Text File | 1997-09-22 | 56.9 KB | 1,810 lines | [ TEXT/ALFA]
## -*-Tcl-*- # ################################################################### # HTML mode - tools for editing HTML documents # # FILE: "htmlEngine.tcl" # created: 96-04-29 21.31.28 # last update: 97-09-17 19.34.12 # Author: Johan Linde # E-mail: <jl@theophys.kth.se> # www: <http://bach.theophys.kth.se/~jl/Alpha.html> # # Version: 2.0 # # Copyright 1996, 1997 by Johan Linde # # This software may be used freely, and distributed freely, as long as the # receiver is not obligated in any way by receiving it. # # If you make improvements to this file, please share them! # # ################################################################### ## proc htmlEngine.tcl {} {} proc htmlIsUnsignedInteger {str1} { return [regexp {^[0-9]+$} [string trim $str1]] } proc htmlIsPositiveInteger {str1} { return [expr ([htmlIsUnsignedInteger $str1] && ![regexp {^0+$} [string trim $str1]])] } proc htmlIsInteger {str} { return [regexp {^-?[0-9]+$} [string trim $str]] } # Checks to see if the current window is empty, except for whitespace. proc htmlIsEmptyFile {} { return [htmlIsWhite [getText 0 [maxPos]]] } # Removes all tags from a string. proc htmlTagStrip {str} { regsub -all {<[^<>]*>} $str "" str return $str } # Quoting of strings for meta tags. proc htmlQuote {str} { regsub -all "#" $str {#;} str regsub -all "\"" $str {#qt;} str regsub -all "<" $str {#lt;} str regsub -all ">" $str {#gt;} str return $str } proc htmlUnQuote {str} { regsub -all {#qt;} $str "\"" str regsub -all {#lt;} $str "<" str regsub -all {#gt;} $str ">" str regsub -all {#;} $str "#" str return $str } # ◊◊◊◊ Change below for new system §8 ◊◊◊◊ # proc htmlRedraw {} { eval sizeWin [lrange [getGeometry] 2 end] } # ◊◊◊◊ end changing for new system §8 ◊◊◊◊ # # Find the version number of a program. # Returns 0 if any problem. proc htmlGetVersion {sig} { set vers [objectProperty 'MACS' vers "obj {want:type(file), seld:$sig, form:fcrt, from:'null'()}"] if {[regexp {vers\(«([0-9]+)} $vers dum vers]} { return [string trimleft [string range $vers 0 1].[string range $vers 2 3] 0] } return 0 } # Checks if the current position is inside the container ELEM. proc htmlIsInContainer {elem} { set exp1 "<${elem}(\[ \t\r\]+\[^<>\]*>|>)" set exp2 "</${elem}>" set pos [getPos] if {![catch {search -s -f 0 -r 1 -i 1 -m 0 $exp1 $pos} res1] && $pos > [lindex $res1 1] && ([catch {search -s -f 0 -r 1 -i 1 -m 0 $exp2 $pos} res2] || [lindex $res1 0] > [lindex $res2 0])} { return 1 } return 0 } # Checks if an element is an INPUT elements. proc htmlIsInputElement {elem} { global htmlElemProc if {[lsearch -exact {TEXT PASSWORD CHECKBOX BUTTON RADIO IMAGE HIDDEN FILE SUBMIT RESET} $elem] >= 0 || [info exists htmlElemProc($elem)] && [lindex $htmlElemProc($elem) 0] == "htmlBuildInputElem"} { return 1 } return 0 } proc htmlCommentStrings {} { if {[htmlIsInContainer SCRIPT] || [htmlIsInContainer STYLE]} { return [list "/* " " */"] } else { return [list "<!-- " " -->"] } } # Create a string for URL mapping in Big Brother. proc htmlURLmap {} { global HTMLmodeVars set urlmap {} foreach hp $HTMLmodeVars(homePages) { set fld "[htmlURLescape [lindex $hp 0] 1]/" regsub -all ":" $fld "/" fld set url [htmlURLescape "[lindex $hp 1][lindex $hp 2]"] lappend urlmap "Msta:“$url”, Mend:“file:///$fld”" append urlmap "," } set urlmap [string trimright $urlmap ","] return $urlmap } # Checks if an app is running. proc htmlCheckRunning {sig} { foreach p [processes] { if {[lindex $p 1] == $sig } { return 1 } } return 0 } # Makes a line for browser error window. proc htmlBrwsErr {fil l lnum ln text path} { return "$fil[format "%$l\s" ""]; Line $lnum:[format "%$ln\s" ""]$text\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t∞$path\r" } proc htmlSetWin {mode} { insertColorEscape 0 1 insertColorEscape [nextLineStart [nextLineStart 0]] 0 newMode $mode select [nextLineStart [nextLineStart 0]] [nextLineStart [nextLineStart [nextLineStart 0]]] setWinInfo dirty 0 setWinInfo read-only 1 scrollUpLine; scrollUpLine } proc htmlIsTextFile {fil cmd} { if {[getFileType $fil] != "TEXT"} { $cmd "[file tail $fil] is not a text file." return 0 } return 1 } proc htmlAllSaved {msg} { set dirty 0 foreach w [winNames] { getWinInfo -w $w arr if {$arr(dirty)} {set dirty 1; break} } if {$dirty} { set yn [eval [concat askyesno $msg]] if {$yn == "yes"} {saveAll} return $yn } return yes } proc htmlIsThereAHomePage {} { global HTMLmodeVars if {![llength $HTMLmodeVars(homePages)]} { alertnote "You must set a home page folder." htmlHomePages } return [llength $HTMLmodeVars(homePages)] } proc htmlWhichHomePage {msg} { global HTMLmodeVars foreach hp $HTMLmodeVars(homePages) { lappend hplist "[lindex $hp 1][lindex $hp 2]" } if {[catch {listpick -p "Select home page to $msg." $hplist} hp] || ![string length $hp]} {error ""} set home [lindex $HTMLmodeVars(homePages) [lsearch -exact $hplist $hp]] if {![file exists [lindex $home 0]] || ![file isdirectory [lindex $home 0]]} { alertnote "Can't find the folder for [lindex $home 1][lindex $home 2]" error "" } return $home } # Determines in which home page folder a URL points to. # If none, return empty string. proc htmlInWhichHomePage {url} { global HTMLmodeVars foreach p $HTMLmodeVars(homePages) { if {[string match "[lindex $p 1][lindex $p 2]*" $url]} {return [lindex $p 0]} } return "" } # Checks if a folder contains a home page folder or an include folder as a subfolder. proc htmlContainHpFolder {folder} { global HTMLmodeVars foreach p $HTMLmodeVars(homePages) { foreach i {0 4} { if {[llength $p] == $i} {continue} if {[string match "$folder:*" "[lindex $p $i]:"] && "[lindex $p $i]:" != "$folder:"} { return 1 } } } return 0 } # Asks for a folder and checks that it is not an alias. proc htmlGetDir {prompt} { while {1} { if {[file isdirectory [set folder [get_directory -p $prompt]]]} { break } else { alertnote "Sorry! Cannot resolve aliases." } } return [string trimright $folder :] } proc htmlNotYet {} { alertnote "Not yet, but coming soon." } proc htmlDisabled {} { alertnote "Disabled function!" error "Disabled function!" } proc htmlSetCase {elem} { global HTMLmodeVars if {$HTMLmodeVars(useLowerCase)} { return [string tolower $elem] } else { return [string toupper $elem] } } # Returns a list of all attributes used in any HTML element. proc htmlGetAllAttrs {} { global htmlElemAttrOptional1 htmlElemAttrRequired1 htmlElemEventHandler1 foreach elem [array names htmlElemAttrOptional1] { if {[info exists htmlElemAttrRequired1($elem)]} { append allHTMLattrs " " $htmlElemAttrRequired1($elem) } append allHTMLattrs " " $htmlElemAttrOptional1($elem) if {[info exists htmlElemEventHandler1($elem)]} { append allHTMLattrs " " [string toupper $htmlElemEventHandler1($elem)] } } return $allHTMLattrs } # Snatch the current selection into htmlCurSel, set flag whether there is one proc htmlGetSel {} { global htmlCurSel htmlIsSel set htmlCurSel [string trim [getSelect]] set htmlIsSel [string length $htmlCurSel] } # Insert one or two carriage returns at the insertion point if any # character preceding the insertion point (on the same line) # is a non-whitespace character. proc htmlOpenCR {indent {extrablankline 0}} { set end [getPos] set start [lineStart $end] set text [getText $start $end] if {![htmlIsWhite $text]} { set r "\r$indent" if {$extrablankline} {append r "\r$indent"} return $r } elseif {$start > 0 } { set prevstart [lineStart [expr $start - 1 ]] set text [getText $prevstart [expr $start - 1]] if {![htmlIsWhite $text] && $extrablankline} { return "\r$indent" } else { return [htmlFirstLineIndent $indent] } } else { return [htmlFirstLineIndent $indent] } } # Insert a carriage return at the insertion point if any # character following the insertion point (on the same line) # is a non-whitespace character. proc htmlCloseCR {indent {start ""}} { if {$start == ""} {set start [selEnd]} if {![htmlIsWhite [getText $start [nextLineStart $start]]]} { return "\r$indent" } } # Insert up to two carriage return at the insertion point depending # on how many blank lines there are after the insertion point. proc htmlCloseCR2 {indent pos} { set blank1 [htmlIsWhite [getText $pos [nextLineStart $pos]]] set blank2 [htmlIsWhite [getText $pos [nextLineStart [nextLineStart $pos]]]] if {!$blank1} { return "\r$indent\r$indent" } elseif {!$blank2} { return "\r$indent" } } proc HTMLelectricSemi {} { global HTMLmodeVars if [isSelection] { deleteSelection } if {!$HTMLmodeVars(electricSemi) || (![htmlIsInContainer SCRIPT] && ![htmlIsInContainer STYLE])} { insertText ";" return } set pos [getPos] set start [lineStart $pos] set text [getText $start $pos] if {[string first "for" $text] != "-1"} { set lefts 0 set rights 0 set len [string length $text] for {set i 0} {$i < $len} {incr i} { case [string index $text $i] in { "(" { incr lefts } ")" { incr rights } } } if {$lefts != $rights} { insertText ";" return } } insertText ";\r" [htmlGetIndent $pos] } #=============================================================================== # Tab key #=============================================================================== # Set up tab mark mechanism. proc htmlTabGoto {directionIndicator} { set searchResult [search -s -n -f $directionIndicator -m 0 -i 1 -r 0 {•} [getPos]] if {![llength $searchResult] || [lindex $searchResult 0] >= [maxPos]} { beep message "Tab mark not found." return 0 } else { goto [lindex $searchResult 0] return 1 } } proc htmlNextTabMark {} { if {[htmlTabGoto 1]} {deleteChar} } proc htmlPreviousTabMark {} { if {[htmlTabGoto 0]} {deleteChar} } # ◊◊◊◊ Change below for new system §18 ◊◊◊◊ # # If current position is inside a tag, complete the tag or attributes # being written. proc htmlWordComplete {} { global htmlPackageToUse htmlElemAttrOptional1 htmlElemAttrOptional3 HTMLmodeVars htmlColorAttr global basicColors htmluserColors htmlSpecColor htmlURLAttr htmlSpecURL HTMLmodeVars global htmlSpecWindow htmlWindowAttr if {[htmlIsInContainer SCRIPT]} {wordCompletion; return} if {[htmlIsInContainer STYLE]} {cssWordComplete; return} set pos [getPos] set allTags [array names htmlElemAttrOptional${htmlPackageToUse}] # Find the tag. if {[catch {search -s -f 0 -r 1 -m 0 {<[^ \t\r<>]+} [expr $pos - 1]} left]} {wordCompletion; return} if {![catch {search -s -f 0 -r 0 -m 0 {>} [expr $pos - 1]} right] && [lindex $right 1] > [lindex $left 1] && [lindex $right 0] < $pos} {wordCompletion; return} set tag [string toupper [string range [eval getText $left] 1 end]] if {$tag == "LI"} { set ltype [htmlFindList] if {$ltype == "UL"} { set tag "LI IN UL" } elseif {$ltype == "OL"} { set tag "LI IN OL" } } set tagBegin [expr [lindex $left 0] + 1] set tagEnd [lindex $left 1] # opening or closing tag set opening 1 if {[string index $tag 0] == "/"} { set tag [string range $tag 1 end] incr tagBegin 1 set opening 0 } # inside < and > or just right of < ? if {![catch {search -s -f 1 -r 0 -m 0 {>} $pos} r1] && ![catch {search -s -f 1 -r 0 -m 0 {<} $pos} l1] && [lindex $r1 0] < [lindex $l1 0]} { set inside 1 } else { set inside 0 } # Are we typing the tag or an attribute? if {$tagEnd == $pos} { # tag set matches "" foreach t $allTags { if {[string match "$tag*" $t]} {lappend matches $t} } if {![llength $matches]} { select $tagBegin $tagEnd } else { set newTag [largestPrefix $matches] if {!$inside} { append newTag > if {$HTMLmodeVars(useTabMarks) && ($opening || [llength $matches] > 1)} {append newTag •} } replaceText $tagBegin $tagEnd [htmlSetCase $newTag] if {!$inside && ($opening || [llength $matches] > 1)} {goto [expr [getPos] - 1 - $HTMLmodeVars(useTabMarks)]} } } else { # Attribute if {!$opening} {return} # are we between quotes to type the attribute value? if {![catch {search -s -f 0 -r 1 -m 0 {=\"[^\"]*\"} [expr $pos - 1]} pos5] && [lindex $pos5 0] > $tagBegin && [lindex $pos5 1] > $pos} { if {![catch {search -s -f 0 -r 1 -m 0 {[ \t\r\"][^ \t\r\"=]+=\"[^\"]*\"} [expr $pos - 1]} attPos] && [lindex $attPos 0] > $tagBegin && [lindex $attPos 1] > $pos} { set txt [getText [expr [lindex $attPos 0] + 1] [lindex $attPos 1]] regexp {([^=]+=)\"([^\"]*)\"} $txt dum attr val set attr [string toupper $attr] set begin [expr [lindex $attPos 0] + 2 + [string length $attr]] set end [expr [lindex $attPos 1] - 1] set choices [htmlGetChoices $tag] if {[lsearch $choices "$attr*"] < 0} { if {[lsearch -exact [concat [htmlGetRequired $tag] [htmlGetOptional $tag 1]] $attr] < 0} {wordCompletion; return} set isChoice 0 if {([lsearch -exact $htmlColorAttr $attr] >= 0 && [lsearch -exact $htmlSpecColor "${tag}!=[string trimright $attr =]"] < 0) || \ [lsearch -exact $htmlSpecColor "${tag}=[string trimright $attr =]"] >= 0} { set choices [concat $basicColors [array names htmluserColors]] } elseif {([lsearch -exact $htmlURLAttr $attr] >= 0 && [lsearch -exact $htmlSpecURL "${tag}!=[string trimright $attr =]"] < 0) || \ [lsearch -exact $htmlSpecURL "${tag}=[string trimright $attr =]"] >= 0} { set choices $HTMLmodeVars(URLs) } elseif {([lsearch -exact $htmlWindowAttr $attr] >= 0 && [lsearch -exact $htmlSpecWindow "${tag}!=[string trimright $attr =]"] < 0) || \ [lsearch -exact $htmlSpecWindow "${tag}=[string trimright $attr =]"] >= 0} { set choices [concat _self _blank _top _parent $HTMLmodeVars(windows)] } else { wordCompletion; return } } else { set val [string toupper $val] set isChoice 1 } set matches "" foreach c $choices { if {$isChoice && [string match "${attr}$val*" $c]} { lappend matches [string range $c [string length $attr] end] } elseif {!$isChoice && [string match "$val*" $c]} { lappend matches $c } } if {![llength $matches]} { select $begin $end } else { set newval [largestPrefix $matches] if {$isChoice} {set newval [htmlSetCase $newval]} replaceText $begin $end $newval } return } } # we are typing the attribute itself. set addSpace 0 if {[set c [lookAt [getPos]]] != " " && $c != ">"} {set addSpace 1} backwardWord set attrBegin [getPos] set attrEnd $pos set attr [string toupper [getText $attrBegin $attrEnd]] set eventAtts [htmlGetEvent $tag] set allAttrs [concat [htmlGetRequired $tag] [htmlGetOptional $tag 1] [string toupper $eventAtts]] set matches "" foreach t $allAttrs { if {[string match "$attr*" $t]} {lappend matches $t} } if {![llength $matches]} { select $attrBegin $attrEnd } else { if {[lookAt [expr $attrBegin - 1]] == "\""} {set newAttr " "} append newAttr [largestPrefix $matches] if {[set i [lsearch [string toupper $eventAtts] "$newAttr*"]] >= 0} { set newAttr [string range [lindex $eventAtts $i] 0 [expr [string length $newAttr] - 1]] } else { set newAttr [htmlSetCase $newAttr] } set backup 1 if {[llength $matches] == 1} { if {[regexp {=} $newAttr]} { append newAttr "\"\"" if {$HTMLmodeVars(useTabMarks)} {append newAttr •} } if {$addSpace} {append newAttr " "; set backup 2} } replaceText $attrBegin $attrEnd $newAttr if {[llength $matches] == 1 && [regexp {=} $newAttr]} {goto [expr [getPos] - $backup - $HTMLmodeVars(useTabMarks)]} } } } # ◊◊◊◊ end changing for new system §18 ◊◊◊◊ # #=============================================================================== # Building tags, including element attributes #=============================================================================== # A couple of functions to get element variables from the right package. proc htmlGetSomeAttrs {item type num1 pkg} { global htmlElem${type}$num1 htmlElem${type}3 if {[catch {set atts [set htmlElem${type}${pkg}($item)]}]} { if {$type == "AttrMore"} { set atts 0 } else { set atts {} } } return $atts } proc htmlGetRequired {item} { global htmlPackageToUse return [htmlGetSomeAttrs $item AttrRequired 1 $htmlPackageToUse] } proc htmlGetOptional {item {all 0}} { global htmlPackageToUse HTMLmodeVars htmlElemHideNetscape htmlElemHideIE set attrs [htmlGetSomeAttrs $item AttrOptional 1 $htmlPackageToUse] if {$all} {return $attrs} if {$HTMLmodeVars(hideStyleAttrs)} { foreach a {CLASS= ID= STYLE=} { if {[set w [lsearch -exact $attrs $a]] >= 0} { set attrs [lreplace $attrs $w $w] } } } if {$htmlPackageToUse == 3} {return $attrs} foreach b {Netscape IE} { if {[set HTMLmodeVars(hide${b})] && [info exists htmlElemHide${b}($item)]} { foreach a [set htmlElemHide${b}($item)] { set attrs [lreplace $attrs [set i [lsearch -exact $attrs $a]] $i] } } } return $attrs } proc htmlGetNumber {item} { global htmlPackageToUse return [htmlGetSomeAttrs $item AttrNumber 1 $htmlPackageToUse] } proc htmlGetChoices {item} { global htmlPackageToUse return [htmlGetSomeAttrs $item AttrChoices 1 $htmlPackageToUse] } proc htmlGetEvent {item} { global htmlPackageToUse return [htmlGetSomeAttrs $item EventHandler 1 $htmlPackageToUse] } proc htmlGetUsed {item {reqatts ""} {optatts ""}} { global htmlPackageToUse if {$htmlPackageToUse == 1} { set num "" } else { set num 3 } set useatts [htmlGetSomeAttrs $item AttrUsed "" $num] if {$reqatts == ""} {set reqatts [htmlGetRequired $item]} if {$optatts == ""} {set optatts [htmlGetOptional $item]} # Add missing required attributes. foreach a $reqatts { if {[lsearch -exact $useatts $a] < 0} { set useatts "$a $useatts" } } # Remove extra attributes foreach a $useatts { if {[lsearch -exact $reqatts $a] < 0 && [lsearch -exact $optatts $a] < 0} { set where [lsearch -exact $useatts $a] set useatts [lreplace $useatts $where $where] } } return $useatts } proc htmlGetAttrMore {item} { global htmlPackageToUse if {$htmlPackageToUse == 1} { set num "" } else { set num 3 } return [htmlGetSomeAttrs $item AttrMore "" $num] } proc htmlOpenElem {elem {used ""} {pos -1}} { global HTMLmodeVars if {$HTMLmodeVars(useBigWindows)} { return [htmlOpenElemWindow $elem $used $pos] } else { return [htmlOpenElemStatusBar $elem $used $pos] } } # Opening or only tag of an element - include attributes # Big window with all attributes. # Return empty string if user clicks "Cancel". proc htmlOpenElemWindow {elem used wrPos {values ""} {addNotUsed 0} {addHidden 0} {absPos ""}} { global HTMLmodeVars htmlColorName htmlElemEventHandler1 global htmluserColors basicColors htmlPackageToUse global htmlURLAttr htmlColorAttr htmlWindowAttr global htmlSpecURL htmlSpecColor htmlSpecWindow set URLs $HTMLmodeVars(URLs) set Windows {_self _top _parent _blank} if {[llength $HTMLmodeVars(windows)]} {append Windows " - " $HTMLmodeVars(windows)} # put users colours first set htmlColors [lsort [array names htmluserColors]] append htmlColors " - " $basicColors if {![string length $used]} {set used $elem} set elem [string toupper $elem] set used [string toupper $used] # get variables for the element set reqatts [htmlGetRequired $used] set numatts [htmlGetNumber $used] set optatts [htmlGetOptional $used] set alloptatts [htmlGetOptional $used 1] set choiceatts [htmlGetChoices $used] set notUsedAtts "" if {$HTMLmodeVars(useAttsApplyToDialogs)} { set allatts [htmlGetUsed $used $reqatts $optatts] foreach a $optatts { if {[lsearch -exact $allatts $a] < 0} { lappend notUsedAtts $a } } } else { set allatts [concat $reqatts $optatts] } set reallyAllAtts [concat $reqatts $alloptatts] foreach a $alloptatts { if {[lsearch -exact $optatts $a] < 0} { lappend hiddenAtts $a } } if {$addNotUsed} { append allatts " $notUsedAtts" set notUsedAtts "" } if {$addHidden} {append allatts " $hiddenAtts"} # optionally include event handlers if {$HTMLmodeVars(inclEventHandler)} { set eventatts [htmlGetEvent $used] append allatts " " $eventatts } else { set eventatts "" } # if there are attributes to ask about, do so set text "<" append text [htmlSetCase $elem] if {![llength $allatts]} {return "$text>"} set maxHeight [expr [lindex [getMainDevice] 3] - 115] set thisPage "Page 1" set widthIndex -1 set heightIndex -1 if {$absPos == ""} {set absPos [getPos]} # build window with attributes set invalidInput 1 while {$invalidInput} { # wrapping set htmlWrapPos [expr $wrPos == -1 ? [lindex [posToRowCol [getPos]] 1] : $wrPos] incr htmlWrapPos [expr [string length $text] + 1] while {1} { if {$used == "LI IN UL" || $used == "LI IN OL"} { set pr LI } else { set pr $used } set box1 "-t {Attributes for $pr} 120 10 450 25" set box2 "-t {Attributes for $pr} 120 10 450 25" set box3 "-t {Attributes for $pr} 120 10 450 25" set page 1 set attrtypes {} set fileIndex "" set colorIndex "" set wpos 10 if {[string length $reqatts]} { lappend box$page -p 120 30 270 31 -t {Required attributes} 10 35 200 50 set hpos 60 } else { set hpos 30 } set attrIndex 2 for {set i 0} {$i < [llength $allatts]} {incr i} { set attr [lindex $allatts $i] if {$i == [llength $reqatts]} { if {$wpos > 20} { incr hpos 20 } lappend box$page -p 120 $hpos 270 [expr $hpos + 1] \ -t {Optional attributes} 10 [expr $hpos + 5] 200 [expr $hpos + 20] set wpos 10 incr hpos 30 } set a2 [string trimright $attr =] if {[string index $attr [expr [string length $attr] - 1]] != "="} { # Flag if {[expr $hpos + 20] > $maxHeight && $wpos < 20 && $page < 3} { incr page set hpos 40 } lappend box$page -c $attr [lindex $values $attrIndex] $wpos $hpos [expr $wpos + 100] [expr $hpos + 15] incr attrIndex if {$wpos > 20} { incr hpos 25 set wpos 10 } else { set wpos 230 } lappend attrtypes flag } elseif {([lsearch -exact $htmlURLAttr $attr] >= 0 && [lsearch -exact $htmlSpecURL "${used}!=$a2"] < 0) || \ [lsearch -exact $htmlSpecURL "${used}=$a2"] >= 0} { # URL if {$wpos > 20} { incr hpos 25 ; set wpos 10} if {[expr $hpos + 45] > $maxHeight && $page < 3} { incr page set hpos 40 } lappend box$page -t $attr 10 $hpos 120 [expr $hpos + 15] \ -e [lindex $values $attrIndex] 120 $hpos 450 [expr $hpos + 15] \ -m [concat [list [lindex $values [expr $attrIndex + 1]] {No value}] $URLs] \ 120 [expr $hpos + 25] 450 [expr $hpos + 35] \ -b "File…" 10 [expr $hpos + 20] 70 [expr $hpos + 40] incr attrIndex 3 incr hpos 50 lappend attrtypes url lappend fileIndex [expr $attrIndex - 1] } elseif {([lsearch -exact $htmlColorAttr $attr] >= 0 && [lsearch -exact $htmlSpecColor "${used}!=$a2"] < 0) || \ [lsearch -exact $htmlSpecColor "${used}=$a2"] >= 0} { # Color attribute if {$wpos > 20} { incr hpos 25 ; set wpos 10} if {[expr $hpos + 25] > $maxHeight && $page < 3} { incr page set hpos 40 } lappend box$page -t $attr 10 $hpos 120 [expr $hpos + 15] \ -e [lindex $values $attrIndex] 120 $hpos 190 [expr $hpos + 15] \ -m [concat [list [lindex $values [expr $attrIndex + 1]] {No value}] $htmlColors] \ 200 $hpos 340 [expr $hpos + 15] \ -b "New Color…" 350 $hpos 450 [expr $hpos + 20] incr attrIndex 3 incr hpos 30 lappend attrtypes color lappend colorIndex [expr $attrIndex - 1] } elseif {([lsearch -exact $htmlWindowAttr $attr] >= 0 && [lsearch -exact $htmlSpecWindow "${used}!=$a2"] < 0) || \ [lsearch -exact $htmlSpecWindow "${used}=$a2"] >= 0} { # Window attribute if {$wpos > 20} { incr hpos 25 ; set wpos 10} if {[expr $hpos + 25] > $maxHeight && $page < 3} { incr page set hpos 40 } lappend box$page -t $attr 10 $hpos 120 [expr $hpos + 15] \ -e [lindex $values $attrIndex] 120 $hpos 240 [expr $hpos + 15] \ -m [concat [list [lindex $values [expr $attrIndex + 1]] {No value}] \ $Windows] \ 250 $hpos 440 [expr $hpos + 15] incr attrIndex 2 incr hpos 30 lappend attrtypes window } elseif {[lsearch $numatts "${attr}*"] >= 0} { # Number if {[expr $hpos + 20] > $maxHeight && $wpos < 20 && $page < 3} { incr page set hpos 40 } if {$attr == "WIDTH="} {set widthIndex $attrIndex} if {$attr == "HEIGHT="} {set heightIndex $attrIndex} lappend box$page -t $attr $wpos $hpos [expr $wpos + 100] [expr $hpos + 15] \ -e [lindex $values $attrIndex] [expr $wpos + 110] $hpos [expr $wpos + 150] [expr $hpos + 15] incr attrIndex if {$wpos > 20} { incr hpos 25 set wpos 10 } else { set wpos 230 } lappend attrtypes number } elseif {[lsearch $choiceatts "${attr}*"] >= 0} { # Choices if {[expr $hpos + 20] > $maxHeight && $wpos < 20 && $page < 3} { incr page set hpos 40 } set matches {} foreach w $choiceatts { if {[string match "${attr}*" $w]} { lappend matches [string range $w [string length $attr] end] } } lappend box$page -t $attr $wpos $hpos [expr $wpos + 100] [expr $hpos + 15] \ -m [concat [list [lindex $values $attrIndex] {No value}] $matches] \ [expr $wpos + 110] $hpos [expr $wpos + 205] [expr $hpos + 15] incr attrIndex if {$wpos > 20} { incr hpos 25 set wpos 10 } else { set wpos 230 } lappend attrtypes choices } else { # Any other if {$wpos > 20} { incr hpos 25 ; set wpos 10} if {[expr $hpos + 20] > $maxHeight && $page < 3} { incr page set hpos 40 } lappend box$page -t $attr 10 $hpos 120 [expr $hpos + 15] \ -e [lindex $values $attrIndex] 120 $hpos 450 [expr $hpos + 15] incr attrIndex incr hpos 25 lappend attrtypes any } } if {$wpos > 20} { incr hpos 25 } if {$page == 1} { set box $box1 } elseif {$page == 2} { set hpos $maxHeight set box " -m \{\{$thisPage\} \{Page 1\} \{Page 2\}\} 10 10 85 30 -n \{Page 1\} $box1 -n \{Page 2\} $box2" } elseif {$page == 3} { set hpos $maxHeight set box " -m \{\{$thisPage\} \{Page 1\} \{Page 2\} \{Page 3\}\} 10 10 85 30 -n \{Page 1\} $box1 -n \{Page 2\} $box2 -n \{Page 3\} $box3" } # Add More button if hidden attrs set moreButton 0 if {[llength $reallyAllAtts] > [llength $allatts]} { set box " -b More… 200 [expr $hpos + 20] 265 [expr $hpos + 40] $box" set moreButton 1 } set values [eval [concat dialog -w 460 -h [expr $hpos + 50] \ -b OK 20 [expr $hpos + 20] 85 [expr $hpos + 40] \ -b Cancel 110 [expr $hpos + 20] 175 [expr $hpos + 40] $box]] # More button clicked? if {[llength $reallyAllAtts] > [llength $allatts] && [lindex $values 2]} { if {[llength $notUsedAtts]} { append allatts " $notUsedAtts" set notUsedAtts "" } else { append allatts " $hiddenAtts" } } # If more button... if {$moreButton} { set values [lreplace $values 2 2] } # If two pages... if {$page > 1} { set thisPage [lindex $values 2] set values [lreplace $values 2 2] } # OK button clicked? if {[lindex $values 0] } { break } # Cancel button clicked? if {[lindex $values 1] } { return} # File button clicked? foreach fl $fileIndex { if {[lindex $values $fl] && [string length [set newFile [htmlGetFile]]]} { set URLs $HTMLmodeVars(URLs) set values [lreplace $values [expr $fl - 1] [expr $fl - 1] [lindex $newFile 0]] if {$used == "IMG" && $fl == 4 && [llength [set widhei [lindex $newFile 1]]]} { if {$widthIndex >= 0} {set values [lreplace $values $widthIndex $widthIndex [lindex $widhei 0]]} if {$heightIndex >= 0} {set values [lreplace $values $heightIndex $heightIndex [lindex $widhei 1]]} } } } # Color button clicked? foreach cl $colorIndex { if {[lindex $values $cl] && [string length [set newcolor [htmlAddNewColor]]]} { set htmlColors [concat [list $newcolor] $htmlColors] set values [lreplace $values [expr $cl - 1] [expr $cl - 1] "$newcolor"] } } } # put everything together set attrtext "" set errtext "" set j 2 for {set i 0} {$i < [llength $attrtypes]} {incr i} { set attr [lindex $allatts $i] switch [lindex $attrtypes $i] { url { set texturl [string trim [lindex $values $j]] set menuurl [lindex $values [expr $j + 1]] if {[string length $texturl]} { append attrtext [htmlWrapTag "[htmlSetCase $attr][htmlAddQuotes [htmlURLescape2 $texturl]]"] htmlAddToCache URLs $texturl } elseif {$menuurl != "No value"} { append attrtext [htmlWrapTag "[htmlSetCase $attr][htmlAddQuotes [htmlURLescape2 $menuurl]]"] } elseif {[lsearch -exact $reqatts $attr] >= 0} { lappend errtext "$attr required." } incr j 3 } color { set colortxt [lindex $values $j] set colorval [lindex $values [expr $j + 1]] if {[string length $colortxt]} { set col [htmlCheckColorNumber $colortxt] if {$col == 0} { lappend errtext "$attr: $colortxt is not a valid color number." } else { append attrtext [htmlWrapTag "[htmlSetCase $attr][htmlAddQuotes $col]"] } } elseif {$colorval != "No value"} { # Users own color? if {[info exists htmluserColors($colorval)]} { set colornum $htmluserColors($colorval) } # Predefined color? if {[info exists htmlColorName($colorval)]} { set colornum $htmlColorName($colorval) } append attrtext [htmlWrapTag "[htmlSetCase $attr][htmlAddQuotes $colornum]"] } elseif {[lsearch -exact $reqatts $attr] >= 0} { lappend errtext "$attr required." } incr j 3 } window { set textwin [string trim [lindex $values $j]] set menuwin [lindex $values [expr $j + 1]] if {[string length $textwin]} { append attrtext [htmlWrapTag "[htmlSetCase $attr][htmlAddQuotes $textwin]"] htmlAddToCache windows $textwin } elseif {$menuwin != "No value"} { append attrtext [htmlWrapTag "[htmlSetCase $attr][htmlAddQuotes $menuwin]"] } elseif {[lsearch -exact $reqatts $attr] >= 0} { lappend errtext "$attr required." } incr j 2 } number { set numval [string trim [lindex $values $j]] if {[string length $numval]} { if {[htmlCheckAttrNumber $used $attr $numval] == 1} { append attrtext [htmlWrapTag "[htmlSetCase $attr][htmlAddQuotes $numval]"] } else { lappend errtext "$attr: [htmlCheckAttrNumber $used $attr $numval]" } } elseif {[lsearch -exact $reqatts $attr] >= 0} { lappend errtext "$attr required." } incr j } choices { set choiceval [lindex $values $j] if {$choiceval != "No value"} { set qchoice [htmlAddQuotes $choiceval] if {($used != "LI IN OL" && $used != "OL") || $attr != "TYPE="} { set qchoice [htmlSetCase $qchoice] } append attrtext [htmlWrapTag "[htmlSetCase $attr]$qchoice"] } elseif {[lsearch -exact $reqatts $attr] >= 0} { lappend errtext "$attr required." } incr j } any { set anyval [lindex $values $j] # Trim only if it's only spaces. if {[string trim $anyval] == ""} {set anyval ""} if {[string length $anyval]} { htmlOpenExtraThings $used $attr $anyval if {[lsearch -exact $eventatts $attr] < 0} { set attr [htmlSetCase $attr] } append attrtext [htmlWrapTag "$attr[htmlAddQuotes $anyval]"] } elseif {[lsearch -exact $reqatts $attr] >= 0} { lappend errtext "$attr required." } incr j } flag { set flagval [lindex $values $j] if {$flagval} { append attrtext [htmlWrapTag [htmlSetCase $attr]] } incr j } } } # If everything is OK, add the attribute text to text. if {![llength $errtext]} { append text $attrtext set invalidInput 0 } else { # Put up alert with the error text. htmlErrorWindow "Invalid input for $used" $errtext } # Some tests that input is ok. if {!$invalidInput} {set invalidInput [htmlFontBaseTest $text alertnote]} if {!$invalidInput && $elem == "A" && [set invalidInput [htmlATest $text alertnote]]} { set text "<[htmlSetCase A]" } if {!$invalidInput && $elem == "FRAMESET" && [set invalidInput [htmlFramesetTest $text alertnote]]} { set text "<[htmlSetCase FRAMESET]" } if {!$invalidInput && $elem == "SPACER" && [set invalidInput [htmlSpacerTest $text alertnote]]} { set text "<[htmlSetCase SPACER]" } if {!$invalidInput && $elem == "AREA" && [set invalidInput [htmlAreaTest $text alertnote]]} { set text "<[htmlSetCase AREA]" } } if {[string length $text] } {append text ">"} return ${text} } proc htmlWrapTag {toadd} { global fillColumn HTMLmodeVars upvar htmlWrapPos wrpos absPos ap if {!$HTMLmodeVars(wordWrap)} {return " $toadd"} incr wrpos [string length $toadd] if {$wrpos > $fillColumn} { set ind [htmlGetIndent $ap] set wrpos [string length "$ind$toadd"] return "\r$ind$toadd" } else { return " $toadd" } } # these two require at least one of several optional attributes proc htmlFontBaseTest {text cmd} { if {[string toupper $text] == "<FONT" || [string toupper $text] == "<BASEFONT" || [string toupper $text] == "<BASE" || [string toupper $text] == "<SPAN"} { eval {$cmd "At least one of the attributes is required."} return 1 } return 0 } # HREF or NAME must be used for A. proc htmlATest {text cmd} { if {![regexp -nocase {href=} $text] && ![regexp -nocase {name=} $text]} { eval {$cmd "At least one of the attributes HREF and NAME must be used."} return 1 } return 0 } # ROWS or COLS must be used for FRAMESET proc htmlFramesetTest {text cmd} { if {![regexp -nocase {rows=} $text] && ![regexp -nocase {cols=} $text]} { eval {$cmd "At least one of the attributes ROWS and COLS must be used."} return 1 } return 0 } # Some checks for SPACER. proc htmlSpacerTest {text cmd} { set horver [regexp -nocase {type=\"(horizontal|vertical)\"} $text] set wh [regexp -nocase {width=|height=} $text] set sz [regexp -nocase {size=} $text] set al [regexp -nocase {align=} $text] set invalidInput 1 if {$horver && ($wh || $al)} { eval {$cmd "WIDTH, HEIGHT and ALIGN should only be used when TYPE=BLOCK."} } elseif {!$horver && $sz} { eval {$cmd "SIZE should only be used when TYPE=HORIZONTAL or VERTICAL."} } elseif {$horver && !$sz} { eval {$cmd "SIZE is required when TYPE=HORIZONTAL or VERTICAL."} } elseif {!$horver && !$wh} { eval {$cmd "WIDTH or HEIGHT is required when TYPE=BLOCK."} } else { set invalidInput 0 } return $invalidInput } # For AREA, either HREF or NOHREF must be used, but not both. proc htmlAreaTest {text cmd} { set hasHref [regexp -nocase {href=} $text] set hasNohref [regexp -nocase {nohref} $text] set hasCoords [regexp -nocase {coords=} $text] set shapeDefault [regexp -nocase {shape=\"default\"} $text] set invalidInput 0 if {($hasHref && $hasNohref) || (!$hasHref && !$hasNohref)} { eval {$cmd "One of the attributes HREF and NOHREF must be used, but not both."} set invalidInput 1 } elseif {!$hasCoords && !$shapeDefault} { eval {$cmd "COORDS= is required if SHAPE≠DEFAULT"} set invalidInput 1 } return $invalidInput } # Adds a NAME= value to cache. proc htmlOpenExtraThings {elem attr val} { if {[lsearch -exact {A MAP} $elem] >= 0 && $attr == "NAME="} { htmlAddToCache URLs "#$val" } if {$elem == "FRAME" && $attr == "NAME="} { htmlAddToCache windows $val } } # Check if a input is a valid number for the element attribute. # Returns 1 if it is, otherwise returns an error message. proc htmlCheckAttrNumber {item attr number} { set attrNumbers [htmlGetNumber $item] set numind [lsearch $attrNumbers "${attr}*"] set numstr [string range [lindex $attrNumbers $numind] [string length $attr] end] regexp {^[-i0-9]+} $numstr minvalue set numstr [string range $numstr [expr [string length $minvalue] + 1] end] regexp {^[-i0-9]+} $numstr maxvalue set procent [string range $numstr [expr [string length $numstr] - 1] end] if {$procent == "%"} { set procerr " or percentage" } else { set procerr "" } if {$minvalue == "-i"} { set errtext "An integer" } elseif {$maxvalue == "i"} { set errtext "A number $minvalue or greater" } else { set errtext "A number in the range $minvalue to $maxvalue" } if {$item == "FONT"} { append errtext " or -6 to +6"} append errtext "$procerr expected." # Is percent allowed? if {[string index $number [expr [string length $number] - 1]] == "%" } { set number [string range $number 0 [expr [string length $number] - 2]] if {$procent != "%"} {return $errtext} } # FONT can take values -6 - +6. Special case. if {$item == "FONT" && [regexp {^(\+|-)[1-6]$} $number]} { return 1} # Is input a number? if {![regexp {^-?[0-9]+$} $number]} {return $errtext} # Is input in the valid range? if {( $maxvalue != "i" && $number > $maxvalue ) || ( $minvalue != "-i" && $number < $minvalue ) } { return $errtext } return 1 } # Add quotes to attribute proc htmlAddQuotes {v} { if {[string range $v 0 0] != "\""} {set v "\"$v"} set vlen [expr [string length $v] - 1] if {[string range $v $vlen $vlen] !="\""} {append v "\""} return $v } # Splits an attribute into its name and value and remove quotes. proc htmlRemoveQuotes {attrStr} { # Is it a flag? if {![string match "*=*" $attrStr]} {return [string toupper $attrStr]} set attr [string range $attrStr 0 [string first "=" $attrStr]] # Get the attribute value. set attrVal [string range $attrStr [expr [string first "=" $attrStr] + 1] end] return [list $attr [string trim $attrVal \"]] } # Returns a list of the attributes not used for the tag at the current position. proc htmlGetAttributes {} { set pos [getPos] if {[catch {search -s -f 0 -r 1 -m 0 {<[^<>]+>} $pos} res] || [lindex $res 1] < $pos} { message "Current position is not at a tag." return } set tag [string trim [lindex [set all [string toupper [eval getText $res]]] 0] "<>"] if {$tag == "LI"} { set ltype [htmlFindList] if {$ltype == "UL"} { set tag "LI IN UL" } elseif {$ltype == "OL"} { set tag "LI IN OL" } } # All INPUT elements are defined differently. Must extract TYPE. if {$tag == "INPUT"} { if {![regexp { TYPE=\"?([^ \t\r\"]+)\"?} $all dum tag]} { message "INPUT element without a TYPE attribute." return } } set ret "" foreach a [concat [htmlGetRequired $tag] [htmlGetOptional $tag 1] [htmlGetEvent $tag]] { set exp "\[ \t\r\n\]+${a}" if {![regexp -nocase $exp $all]} { lappend ret $a } } if {$ret == ""} {message "No attributes."} return $ret } # Inserts an attribute in a tag at the current position. proc htmlInsertAttributes {{attrList ""}} { global HTMLmodeVars fillColumn set useMarks $HTMLmodeVars(useTabMarks) if {$attrList == "" && ([set l [htmlGetAttributes]] == "" || [catch {listpick -p "Select attributes" -l $l} attrList] || $attrList == "") } {return} foreach attr $attrList { set epos [expr [lindex [search -s -f 0 -r 1 -m 0 {<[^<>]+>} [getPos]] 1] - 1] if {[expr [lindex [posToRowCol $epos] 1] + [string length $attr]] > $fillColumn && $HTMLmodeVars(wordWrap)} { set text "\r[htmlGetIndent $epos]" } else { set text " " } append text $attr if {[string match "*=" $attr]} { append text "\"\"" if {$useMarks} {append text •} } set x [expr $epos - 3] if {[string match "*•" [set etxt [getText $x $epos]]]} { set p [expr $x + 1] if {$useMarks} { if {[string match "*=" $attr]} { set text [string range $text 0 [expr [string length $text] - 3]]•\"• } else { append text • } } replaceText [expr $p + 1] $epos $text } else { goto $epos insertText $text if {[regexp {=} $text]} {goto [expr + [getPos] - 1 - $useMarks]} } } } #=============================================================================== # Element build routines #=============================================================================== # Closing tag of an element proc htmlCloseElem {theElem} { return "</[htmlSetCase $theElem]>" } proc htmlTag {str} { global htmlElemProc set elem [lindex $str 1] if {[htmlIsInContainer STYLE]} { if {[htmlIsInputElement $elem]} {set elem INPUT} replaceText [getPos] [selEnd] $elem } elseif {[info exists htmlElemProc($elem)]} { eval $htmlElemProc($elem) } else { eval $str } } # Build elements with only a opening tag. proc htmlBuildOpening {ftype {begCR 0} {endCR 0} {attr ""}} { set text1 "" set indent [htmlGetIndent [getPos]] if {$begCR} { set text1 [htmlOpenCR $indent] } set text [htmlOpenElem $ftype $attr] if {![string length $text]} {return} if {$endCR} { append text [htmlCloseCR $indent] } insertText $text1 $text } # This is used for almost all containers proc htmlBuildElem {ftype {attr ""}} { global HTMLmodeVars htmlCurSel htmlIsSel if {![string length [set text [htmlOpenElem $ftype $attr]]]} {return} htmlGetSel append text $htmlCurSel set currpos [expr [getPos] + [string length $text]] append text [htmlCloseElem $ftype] if {!$htmlIsSel && $HTMLmodeVars(useTabMarks)} {append text "•"} if {$htmlIsSel} { replaceText [getPos] [selEnd] $text } else { insertText $text goto $currpos } } # This is used for elements that should be surrounded by newlines proc htmlBuildCRElem {ftype {extrablankline 0} {attr ""}} { global htmlCurSel htmlIsSel HTMLmodeVars if {![string length [set text2 [htmlOpenElem $ftype $attr 0]]]} {return} set indent [htmlFindNextIndent] set text [htmlOpenCR $indent $extrablankline] append text $text2 htmlGetSel append text $htmlCurSel set currpos [expr [getPos] + [string length $text]] append text [htmlCloseElem $ftype] if {$extrablankline} { set cr2 [htmlCloseCR2 $indent [selEnd]] } else { set cr2 [htmlCloseCR $indent] } append text $cr2 if {!$htmlIsSel && $HTMLmodeVars(useTabMarks)} {append text "•"} if {$htmlIsSel} { deleteSelection } insertText $text if {!$htmlIsSel} { goto $currpos } } # This is used for elements that should be surrounded by empty lines proc htmlBuildCR2Elem {ftype {attr ""}} { global HTMLmodeVars htmlCurSel htmlIsSel htmlGetSel # Check if user has skipped an attribute which can't be skipped. if {![string length [set text2 [htmlOpenElem $ftype $attr 0]]]} {return} set indent [htmlFindNextIndent] set text [htmlOpenCR $indent 1] append text $text2 if {[info exists HTMLmodeVars(indent${ftype})] && $HTMLmodeVars(indent${ftype})} { regsub -all "\r" $htmlCurSel "\r\t" htmlCurSel set exindent "\t" } else { set exindent "" } if {$htmlIsSel || ($ftype != "SCRIPT" && $ftype != "STYLE")} { append text "\r${indent}${exindent}$htmlCurSel" } else { append text "\r${indent}<!-- /* Hide content from old browsers */\r${indent}" } set currpos [expr [getPos] + [string length $text]] append text \r$indent set pre(SCRIPT) "//"; set pre(STYLE) "/*"; set post(SCRIPT) ""; set post(STYLE) "*/" if {!$htmlIsSel && ($ftype == "SCRIPT" || $ftype == "STYLE")} {append text "$pre($ftype) end hiding content from old browsers $post($ftype) -->\r$indent"} append text [htmlCloseElem $ftype] append text [htmlCloseCR2 $indent [selEnd]] if {!$htmlIsSel && $HTMLmodeVars(useTabMarks)} {append text "•"} if {$htmlIsSel} { deleteSelection } insertText $text if {!$htmlIsSel} { goto $currpos } } # Determines which list the current position is inside. proc htmlFindList {} { set listType "" foreach l [list UL OL DIR MENU] { set ex "<${l}(\[ \\t\\r\]+\[^>\]*>|>)" set listOpening [search -s -f 0 -i 1 -r 1 -m 0 -n $ex [getPos]] set ex2 </$l> set listClosing [search -s -f 0 -i 1 -r 1 -m 0 -n $ex2 [getPos]] # Search until a single list opening is found. while {[string length $listOpening] && [string length $listClosing] && [lindex $listClosing 0] > [lindex $listOpening 0]} { set listOpening [search -s -f 0 -i 1 -r 1 -m 0 -n $ex [expr [lindex $listOpening 0] - 1]] set listClosing [search -s -f 0 -i 1 -r 1 -m 0 -n $ex2 [expr [lindex $listClosing 0] - 1]] } if {[string length $listOpening]} { lappend listType "$listOpening $l" } } set ltype [lindex [lindex $listType 0] 2] set lnum [lindex [lindex $listType 0] 0] for {set i 1} {$i < [llength $listType]} {incr i} { if {[lindex [lindex $listType $i] 0] > $lnum} { set ltype [lindex [lindex $listType $i] 2] set lnum [lindex [lindex $listType $i] 0] } } return $ltype } # Choose an item from Use Attributes menu. proc htmlChooseUseAttr {} { global htmlPackageToUse htmlElemAttrOptional1 htmlElemAttrOptional3 foreach a [array names htmlElemAttrOptional$htmlPackageToUse] { if {[llength [set htmlElemAttrOptional${htmlPackageToUse}($a)]]} {lappend htmlPossibleToUse $a} } if {![catch {listpick -p "Choose HTML element" [lsort $htmlPossibleToUse]} elem] && $elem != ""} {htmlUseAttributes $elem} } # Customize list of attributes which get asked about proc htmlUseAttributes {item} { global HTMLmodeVars htmlPackageToUse modifiedVars global htmlElemAttrUsed htmlElemAttrUsed3 global htmlElemAttrMore htmlElemAttrMore3 set reqattrs [htmlGetRequired $item] set askformore [htmlGetAttrMore $item] set optatts [htmlGetOptional $item 1] set used [htmlGetUsed $item $reqattrs $optatts] set attrnumber [llength $optatts] set height [expr 95 + (( $attrnumber - 1) / 3 + 1) * 20] set box "-w 400 -h $height -b OK 20 [expr $height - 30] 85 [expr $height - 10] \ -b Cancel 110 [expr $height - 30] 175 [expr $height - 10] \ -t {Select the optional attributes you want for $item} 10 10 450 30 " lappend box -t {Ask for more?} 10 [expr $height - 55] 110 [expr $height - 40] \ -r Yes $askformore 120 [expr $height - 55] 160 [expr $height - 40] \ -r No [expr !$askformore] 180 [expr $height - 55] 220 [expr $height - 40] # see which attributes were used previously set wpos 10 set hpos 35 foreach attr $optatts { lappend box -c [string trimright $attr =] [expr ([lsearch -exact $used $attr] >= 0)] $wpos $hpos [expr $wpos + 120] [expr $hpos + 15] set wpos [expr $wpos + 130] if {$wpos > 310} { set wpos 10 set hpos [expr $hpos + 20] } } # get the new ones wanted set newatts [eval [concat dialog $box]] set newuse {} if {[lindex $newatts 0]} { for {set i 0} {$i < $attrnumber} {incr i} { if {[lindex $newatts [expr $i + 4]]} { lappend newuse [lindex $optatts $i] } } set newuse [concat $reqattrs $newuse] if {$htmlPackageToUse == 1} { set num "" } else { set num 3 } set htmlElemAttrUsed${num}($item) $newuse addArrDef htmlElemAttrUsed$num $item $newuse set htmlElemAttrMore${num}($item) [lindex $newatts 2] addArrDef htmlElemAttrMore$num $item [lindex $newatts 2] } } #=============================================================================== # Indentation #=============================================================================== proc HTMLindentLine {} { if {[htmlIsInContainer STYLE] || [htmlIsInContainer SCRIPT]} {CindentLine; return} if {[htmlIsInContainer PRE]} {return} set previndent [htmlFindIndent] set thisLine [string trimleft [getText [set lstart [lineStart [getPos]]] [set lend [expr [nextLineStart [getPos]] - 1]]]] set thisIndent [htmlGetIndent [getPos]] if {$thisIndent != $previndent} {replaceText $lstart $lend "$previndent$thisLine"} } # Find the indentation the current line should have. proc htmlFindIndent {{pos0 ""}} { global htmlIndentElements HTMLmodeVars set indent "" foreach i $htmlIndentElements { if {$HTMLmodeVars(indent$i)} {lappend indent $i} } # Find previous non-blank line. if {$pos0 == ""} {set pos0 [getPos]} set pos [expr [lineStart $pos0] - 1] while {$pos >= 0 && [regexp {^[ \t]*$} [getText [lineStart $pos] $pos]]} { set pos [expr [lineStart $pos] - 1] } set pos [expr $pos >= 0 ? $pos : 0] # Get indentation on that line. set previndent [htmlGetIndent $pos] # Find last tag on or before that line. if {[catch {search -s -f 0 -m 0 -r 1 {<([^<>]+)>} $pos} tag] || [lindex $tag 1] < [lineStart $pos] || ( [lindex $tag 0] < [lineStart $pos0] && [lindex $tag 1] > [lineStart $pos0])} { set tag "" } else { set tag [string trim [eval getText $tag] "<>"] } set tag [string toupper [lindex $tag 0]] # Add a tab to indentation? if {[lsearch -exact $indent $tag] >= 0} { append previndent "\t" } # Find last tag on current line. set tag "" set lstart [lineStart $pos0] set lend [expr ([set npos [nextLineStart $pos0]] <= $lstart) ? $lstart : $npos - 1] regexp {<([^<>]+)>} [getText $lstart $lend] dum tag set tag [string toupper [lindex $tag 0]] # Remove a tab from indentation? if {[string index $tag 0] == "/" && [lsearch -exact $indent [string range $tag 1 end]] >= 0} { set previndent [htmlReduceIndent $previndent] } return $previndent } # Find the indentation the next line should have. proc htmlFindNextIndent {{pos0 ""}} { global HTMLmodeVars htmlIndentElements set indent "" foreach i $htmlIndentElements { if {$HTMLmodeVars(indent$i)} {lappend indent $i} } if {$pos0 == ""} {set pos0 [getPos]} set ind [htmlFindIndent $pos0] # Find last tag before pos0 on current line. set tag "" set lstart [lineStart $pos0] # set lend [expr ([set npos [nextLineStart $pos0]] <= $lstart) ? $lstart : $npos - 1] regexp {<([^<>]+)>} [getText $lstart $pos0] dum tag set tag [string toupper [lindex $tag 0]] # Remove a tab from indentation? if {[lsearch -exact $indent $tag] >= 0} {append ind "\t"} return $ind } # get the leading whitespace of the current line proc htmlGetIndent { pos } { set res [search -s -n -f 1 -r 1 "^\[ \t\]*" [lineStart $pos]] return [htmlIndentConvert [eval getText $res]] } # convert it to minimal form: tabs then spaces. proc htmlIndentConvert {indent} { getWinInfo a set sp [string range " " 1 $a(tabsize) ] regsub -all $sp $indent "\t" indent regsub -all "\[ \]+\t" $indent "\t" indent return $indent } # Removes tabsize whitespace. proc htmlReduceIndent {indent} { getWinInfo a set sp [string range " " 1 $a(tabsize) ] regsub -all "\t" $indent $sp indent set indent [string range $indent $a(tabsize) end] regsub -all $sp $indent "\t" indent regsub -all "\[ \]+\t" $indent "\t" indent return $indent } proc htmlFirstLineIndent {indent} { if {![htmlIsWhite [set text [getText [lineStart [getPos]] [getPos]]]]} {return $indent} set text [htmlIndentConvert $text] return [string range $indent [string length $text] end] } #=============================================================================== # Tidy up source #=============================================================================== proc htmlReformatParagraph {} {htmlTidyUp paragraph} proc htmlReformatDocument {} {htmlTidyUp document} proc htmlTidyUp {where} { global HTMLmodeVars fillColumn htmlElemProc htmlIndentElements message "Reformatting…" set oldfillColumn $fillColumn getWinInfo a set tab $a(tabsize) if {$where == "paragraph"} { if {[isSelection]} { set startPos [getPos] set endPos [selEnd] } else { if {[catch {search -s -f 0 -m 0 -r 1 {^[ \t]*$} [getPos]} sp]} {set sp 0} set startPos [nextLineStart [lindex $sp 1]] if {[catch {search -s -f 1 -m 0 -r 1 {^[ \t]*$} [getPos]} sp]} {set sp "0 [maxPos]"} set endPos [expr [lindex $sp 1] < [maxPos] ? [lindex $sp 1] + 1 : [maxPos]] } set ind [htmlFindIndent $startPos] set fillColumn [expr $oldfillColumn - $tab * [string length $ind]] set cr 2 } else { set startPos 0 set endPos [maxPos] set ind "" set cr 0 } # Remember position set srem [expr [set pos [getPos]] - 20 < $startPos ? $startPos : $pos - 20] set remember_str [quoteExpr2 [getText $srem $pos ]] regsub -all {\?} $remember_str {\\?} remember_str regsub -all "\[ \t\r\]+" $remember_str {[ \t\r]+} remember_str # To handle indentation set indList "" foreach i $htmlIndentElements { if {$HTMLmodeVars(indent$i)} {lappend indList $i} } # These tags should have a blank line before set blBef {TITLE HEAD BODY STYLE H1 H2 H3 H4 H5 H6 P BLOCKQUOTE DIV CENTER PRE MULTICOL OBJECT NOEMBED UL OL DIR MENU DL FORM SELECT TABLE TR FRAMESET NOFRAMES MAP APPLET SCRIPT NOSCRIPT LAYER NOLAYER} # These tags should have a cr before set crBef {/HTML /HEAD /BODY /STYLE /P /BLOCKQUOTE /DIV ADDRESS /CENTER /PRE /MULTICOL HR BASEFONT MARQUEE /OBJECT BGSOUND /NOEMBED /UL /OL /DIR /MENU LI /DL DT /FORM /SELECT OPTION TEXTAREA KEYGEN /TABLE /TR CAPTION COL COLGROUP THEAD TBODY TFOOT /FRAMESET FRAME /NOFRAMES /MAP AREA /APPLET PARAM /SCRIPT /NOSCRIPT /LAYER ILAYER /NOLAYER BASE ISINDEX LINK META !--} # These tags should have a blank line after set blAft {/TITLE /HEAD /BODY /STYLE /H1 /H2 /H3 /H4 /H5 /H6 /P /BLOCKQUOTE /DIV /CENTER /PRE /MULTICOL /OBJECT /NOEMBED /UL /OL /DIR /MENU /DL /FORM /SELECT /TABLE /TR /FRAMESET /NOFRAMES /MAP /APPLET /SCRIPT /NOSCRIPT /LAYER /NOLAYER} # These tags should have a cr after set crAft {HTML /HTML HEAD BODY STYLE P BLOCKQUOTE DIV /ADDRESS CENTER PRE MULTICOL BR HR WBR BASEFONT /MARQUEE OBJECT BGSOUND NOEMBED UL OL DIR MENU /LI DL /DD FORM INPUT SELECT OPTION /TEXTAREA KEYGEN TABLE TR /CAPTION COL COLGROUP THEAD TBODY TFOOT FRAMESET FRAME NOFRAMES MAP AREA APPLET PARAM SCRIPT NOSCRIPT LAYER /ILAYER NOLAYER BASE ISINDEX LINK META !--} # Custom elements foreach c [array names htmlElemProc] { switch [lindex $htmlElemProc($c) 0] { htmlBuildCR2Elem { lappend blBef $c lappend crBef /$c lappend blAft /$c lappend crAft $c } htmlBuildCRElem { if {[lindex $htmlElemProc($c) 2] == "1"} { lappend blBef $c lappend blAft /$c } else { lappend crBef $c lappend crAft /$c } } htmlBuildOpening { if {[lindex $htmlElemProc($c) 2] == "1"} {lappend crBef $c} if {[lindex $htmlElemProc($c) 3] == "1"} {lappend crAft $c} } } } set all [concat $blBef $blAft $crBef $crAft] set bef [concat $blBef $crBef] set aft [concat $blAft $crAft] set pos $startPos set tmp "" set text "" while {![catch {search -s -f 1 -m 0 -r 1 {(<!--|<[^<>]+>)} $pos} pos1] && [lindex $pos1 1] <= $endPos} { set tag [string toupper [lindex [set wholeTag [string trim [eval getText $pos1] "<>"]] 0]] if {$tag != "!--"} { set w "" set i {0 0} # To avoid line breaks inside attributes while {[regexp -indices {=\"[^ \"]* [^\"]*\"} $wholeTag i]} { append w [string range $wholeTag 0 [expr [lindex $i 0] - 1]] regsub -all "\[ \t\r\]+" [string range $wholeTag [lindex $i 0] [lindex $i 1]] "" w1 append w $w1 set wholeTag [string range $wholeTag [expr [lindex $i 1] + 1] end] } set wholeTag $w$wholeTag } append tmp [getText $pos [lindex $pos1 0]] set pos [lindex $pos1 1] if {[lsearch $all $tag] < 0} { append tmp <$wholeTag> continue } # cr or blank line before tag if {[lsearch $bef $tag] >= 0} { regsub -all "\[ \t\]*\r\[ \t\]*" [string trim $tmp] " " tmp set tmp [string trimright [breakIntoLines $tmp]] regsub -all "" $tmp " " tmp regsub -all "\r" $tmp "\r$ind" tmp if {![htmlIsWhite $tmp]} {set cr 0; append text $ind} append text $tmp set ble [lsearch $blBef $tag] if {$cr == 1 && $ble >= 0 && ([string index $tag 0] != "/" || [lsearch $indList [string range $tag 1 end]] < 0)} { append text $ind } if {$cr == 0} { append text \r incr cr if {$cr == 1 && $ble >= 0} {append text $ind} } if {$ble >= 0 && $cr < 2} {append text \r; incr cr} set tmp <$wholeTag> # Take care of comments separately if {$tag == "!--"} { set tmp "<!--" if {[catch {search -s -f 1 -m 0 -r 1 -i 1 -- "-->" $pos} pos2]} {set pos2 "0 $endPos"} append text $ind$tmp[getText $pos [set pos [lindex $pos2 1]]] set tmp "" set cr 0 } # The contents of these tags should be left untouched if {[lsearch {SCRIPT STYLE PRE} $tag] >= 0} { set tag /$tag regsub -all "" $tmp " " tmp if {[catch {search -s -f 1 -m 0 -r 1 -i 1 "<$tag>" $pos} pos2]} {set pos2 "0 $endPos"} append text $ind$tmp[getText $pos [set pos [lindex $pos2 1]]] set tmp "" set cr 0 } } else { append tmp <$wholeTag> } # cr or blank line after tag if {[lsearch $aft $tag] >= 0} { if {[string index $tag 0] == "/" && [lsearch $indList [string range $tag 1 end]] >= 0} { set ind [string range $ind 1 end] set fillColumn [expr $oldfillColumn - $tab * [string length $ind]] } regsub -all "\[ \t\]*\r\[ \t\]*" [string trim $tmp] " " tmp set tmp [string trimright [breakIntoLines $tmp]] regsub -all "" $tmp " " tmp regsub -all "\r" $tmp "\r$ind" tmp if {![htmlIsWhite $tmp]} {set cr 0; append text $ind} append text $tmp set bla [lsearch $blAft $tag] if {[lsearch $indList $tag] >= 0} { append ind \t set fillColumn [expr $oldfillColumn - $tab * [string length $ind]] } if {$cr == 0} { append text \r incr cr if {$cr == 1 && $bla >= 0} {append text $ind} } if {$bla >= 0 && $cr < 2} {append text \r; incr cr} set tmp "" } } # Add what's left if {$tmp != "" || $pos < $endPos} { if {$pos < $endPos} {append tmp [getText $pos $endPos]} regsub -all "\[ \t\]*\r\[ \t\]*" [string trim $tmp] " " tmp set tmp [string trimright [breakIntoLines $tmp]] regsub -all "" $tmp " " tmp regsub -all "\r" $tmp "\r$ind" tmp if {![htmlIsWhite $tmp]} {append text $ind} append text $tmp if {![htmlIsWhite $tmp]} {append text \r} } replaceText $startPos $endPos $text set fillColumn $oldfillColumn # Go back to previous position. if { $remember_str != "" } { regexp -indices $remember_str [getText $startPos [set end [getPos]]] wholematch set p [expr [info exists wholematch] ? [expr $startPos + 1 + [lindex $wholematch 1]] : $end] goto [expr $p >= $end ? $end -1 : $p] } }